﻿using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using XFControls.XFPanels.XFPanelItems;
using System.Collections.Generic;

#pragma warning disable 1591
#pragma warning disable 219
#pragma warning disable 168

// ReSharper disable InconsistentNaming
// ReSharper disable UnaccessedField.Local
// ReSharper disable EnumUnderlyingTypeIsInt
// ReSharper disable PossibleNullReferenceException
// ReSharper disable BitwiseOperatorOnEnumWihtoutFlags
// ReSharper disable EmptyGeneralCatchClause
// ReSharper disable RedundantAssignment

namespace XFControls.Utils
{
    public class TextEventArgs : EventArgs
    {
        public TextEventArgs(string text)
        {
            Text = text;
        }

        public string Text { get; set; }
    }

    public interface IUpdateable : IDisposable
    {
        bool Show { get; set; }
        void StartUpdates();
        int GetNumber();
        void OnClick();
        event EventHandler Updated;
    }

    public struct BlendFunction
    {
        public byte BlendOp;
        public byte BlendFlags;
        public byte SourceConstantAlpha;
        public byte AlphaFormat;
    }

    public struct TRIVERTEX
    {
        private int x;
        private int y;
        private ushort Red;
        private ushort Green;
        private ushort Blue;
        private ushort Alpha;

        public TRIVERTEX(int x, int y, Color color)
            : this(x, y, color.R, color.G, color.B, color.A)
        {
        }

        public TRIVERTEX(int x, int y, ushort red, ushort green, ushort blue, ushort alpha)
        {
            this.x = x;
            this.y = y;
            Red = (ushort)(red << 8);
            Green = (ushort)(green << 8);
            Blue = (ushort)(blue << 8);
            Alpha = (ushort)(alpha << 8);
        }
    }

    public struct GRADIENT_RECT
    {
        private uint UpperLeft;
        private uint LowerRight;

        public GRADIENT_RECT(uint ul, uint lr)
        {
            UpperLeft = ul;
            LowerRight = lr;
        }
    }

    public enum BlendOperation : byte
    {
        AC_SRC_OVER = 0x00
    }

    public enum BlendFlags : byte
    {
        Zero = 0x00
    }

    public enum SourceConstantAlpha : byte
    {
        Transparent = 0x00,
        Opaque = 0xFF
    }

    public enum AlphaFormat : byte
    {
        AC_SRC_ALPHA = 0x01
    }

    public enum CachedImageType
    {
        Icon,
        Picture,
        ProfileHeader
    }

    public enum ScreenResolution
    {
        QVGA,
        VGA,
        WVGA,
        RotatedQVGA,
        RotatedVGA,
        RotatedWVGA,
        Unknown
    }

    public enum GradientFillDirection
    {
        Horizontal = 0x00000000,
        Vertical = 0x00000001
    }

    public class PlatformAPIs
    {
        [DllImport("coredll.dll")]
        public static extern Int32 AlphaBlend(IntPtr hdcDest,
                                              Int32 xDest,
                                              Int32 yDest,
                                              Int32 cxDest,
                                              Int32 cyDest,
                                              IntPtr hdcSrc,
                                              Int32 xSrc,
                                              Int32 ySrc,
                                              Int32 cxSrc,
                                              Int32 cySrc,
                                              BlendFunction blendFunction);

        [DllImport("coredll.dll")]
        public static extern bool GradientFill(IntPtr hdc,
                                               TRIVERTEX[] pVertex,
                                               uint dwNumVertex,
                                               GRADIENT_RECT[] pMesh,
                                               uint dwNumMesh,
                                               uint dwMode);
    }

    public enum PixelFormatID : int
    {
        PixelFormatIndexed = 0x00010000, // Indexes into a palette 
        PixelFormatGDI = 0x00020000, // Is a GDI-supported format 
        PixelFormatAlpha = 0x00040000, // Has an alpha component 
        PixelFormatPAlpha = 0x00080000, // Pre-multiplied alpha 
        PixelFormatExtended = 0x00100000, // Extended color 16 bits/channel 
        PixelFormatCanonical = 0x00200000,

        PixelFormatUndefined = 0,
        PixelFormatDontCare = 0,

        PixelFormat1bppIndexed = (1 | (1 << 8) | PixelFormatIndexed | PixelFormatGDI),
        PixelFormat4bppIndexed = (2 | (4 << 8) | PixelFormatIndexed | PixelFormatGDI),
        PixelFormat8bppIndexed = (3 | (8 << 8) | PixelFormatIndexed | PixelFormatGDI),
        PixelFormat16bppRGB555 = (5 | (16 << 8) | PixelFormatGDI),
        PixelFormat16bppRGB565 = (6 | (16 << 8) | PixelFormatGDI),
        PixelFormat16bppARGB1555 = (7 | (16 << 8) | PixelFormatAlpha | PixelFormatGDI),
        PixelFormat24bppRGB = (8 | (24 << 8) | PixelFormatGDI),
        PixelFormat32bppRGB = (9 | (32 << 8) | PixelFormatGDI),
        PixelFormat32bppARGB = (10 | (32 << 8) | PixelFormatAlpha | PixelFormatGDI | PixelFormatCanonical),
        PixelFormat32bppPARGB = (11 | (32 << 8) | PixelFormatAlpha | PixelFormatPAlpha | PixelFormatGDI),
        PixelFormat48bppRGB = (12 | (48 << 8) | PixelFormatExtended),
        PixelFormat64bppARGB = (13 | (64 << 8) | PixelFormatAlpha | PixelFormatCanonical | PixelFormatExtended),
        PixelFormat64bppPARGB = (14 | (64 << 8) | PixelFormatAlpha | PixelFormatPAlpha | PixelFormatExtended),
        PixelFormatMax = 15
    }

    // Pulled from imaging.h in the Windows Mobile 5.0 Pocket PC SDK 
    public enum BufferDisposalFlag : int
    {
        BufferDisposalFlagNone,
        BufferDisposalFlagGlobalFree,
        BufferDisposalFlagCoTaskMemFree,
        BufferDisposalFlagUnmapView
    }

    // Pulled from imaging.h in the Windows Mobile 5.0 Pocket PC SDK 
    public enum InterpolationHint : int
    {
        InterpolationHintDefault,
        InterpolationHintNearestNeighbor,
        InterpolationHintBilinear,
        InterpolationHintAveraging,
        InterpolationHintBicubic
    }

    [Flags]
    public enum ImageLockMode
    {
        ImageLockModeRead = 0x0001,
        ImageLockModeWrite = 0x0002,
        ImageLockModeUserInputBuf = 0x0004,
    } ;

#pragma warning disable 0649
    // Pulled from gdiplusimaging.h in the Windows Mobile 5.0 Pocket PC SDK 
    public struct BitmapData
    {
        public uint Width;
        public uint Height;
        public int Stride;
        public PixelFormatID PixelFormat;
        public IntPtr Scan0;
        public IntPtr Reserved;
    }

    // Pulled from imaging.h in the Windows Mobile 5.0 Pocket PC SDK 
    public struct ImageInfo
    {
        public uint GuidPart1; // I am being lazy here, I don't care at this point about the RawDataFormat GUID 
        public uint GuidPart2; // I am being lazy here, I don't care at this point about the RawDataFormat GUID 
        public uint GuidPart3; // I am being lazy here, I don't care at this point about the RawDataFormat GUID 
        public uint GuidPart4; // I am being lazy here, I don't care at this point about the RawDataFormat GUID 
        public PixelFormatID pixelFormat;
        public uint Width;
        public uint Height;
        public uint TileWidth;
        public uint TileHeight;
        public double Xdpi;
        public double Ydpi;
        public uint Flags;
    }
#pragma warning restore 0649

    [StructLayout(LayoutKind.Sequential)]
    public struct SHFILEINFO
    {
        public IntPtr hIcon;
        public IntPtr iIcon;
        public uint dwAttributes;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
        public string szDisplayName;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
        public string szTypeName;
    } ;

    public class Win32
    {
        public const uint SHGFI_ICON = 0x100;
        public const uint SHGFI_LARGEICON = 0x0; // 'Large icon
        public const uint SHGFI_SMALLICON = 0x1; // 'Small icon

        [DllImport("coredll.dll")]
        public static extern IntPtr SHGetFileInfo(string pszPath,
                                                  uint dwFileAttributes,
                                                  ref SHFILEINFO psfi,
                                                  uint cbSizeFileInfo,
                                                  uint uFlags);

        [DllImport("coredll.dll")]
        public static extern bool BitBlt(IntPtr hdcDest, int nxDest, int dyDest, int nWidth, int nHeight, IntPtr hdcSrc, int nxSrc, int nySrc, ERop rop);

        public enum ERop : uint
        {
            SRCCOPY = 0x00CC0020,	/* dest = source                   */
            SRCPAINT = 0x00EE0086,	/* dest = source OR dest           */
            SRCAND = 0x008800C6,	/* dest = source AND dest          */
            SRCINVERT = 0x00660046,	/* dest = source XOR dest          */
            SRCERASE = 0x00440328,	/* dest = source AND (NOT dest )   */
            NOTSRCCOPY = 0x00330008,	/* dest = (NOT source)             */
            NOTSRCERASE = 0x001100A6,	/* dest = (NOT src) AND (NOT dest) */
            MERGECOPY = 0x00C000CA,	/* dest = (source AND pattern)     */
            MERGEPAINT = 0x00BB0226,	/* dest = (NOT source) OR dest     */
            PATCOPY = 0x00F00021,	/* dest = pattern                  */
            PATPAINT = 0x00FB0A09,	/* dest = DPSnoo                   */
            PATINVERT = 0x005A0049,	/* dest = pattern XOR dest         */
            DSTINVERT = 0x00550009,	/* dest = (NOT dest)               */
            BLACKNESS = 0x00000042,	/* dest = BLACK                    */
            WHITENESS = 0x00FF0062,	/* dest = WHITE                    */
        }
    }


    // Pulled from imaging.h in the Windows Mobile 5.0 Pocket PC SDK 
    [ComImport, Guid("327ABDA7-072B-11D3-9D7B-0000F81EF32E"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    [ComVisible(true)]
    public interface IImagingFactory
    {
        uint CreateImageFromStream(); // This is a place holder, note the lack of arguments 
        uint CreateImageFromFile(string filename, out IImage image);
        // We need the MarshalAs attribute here to keep COM interop from sending the buffer down as a Safe Array. 
        uint CreateImageFromBuffer([MarshalAs(UnmanagedType.LPArray)] byte[] buffer, uint size,
                                   BufferDisposalFlag disposalFlag, out IImage image);

        //uint CreateImageFromBuffer(IntPtr buffer, uint size, BufferDisposalFlag disposalFlag, out IImage image);
        uint CreateNewBitmap(uint width, uint height, PixelFormatID pixelFormat, out IBitmapImage bitmap);

        uint CreateBitmapFromImage(IImage image, uint width, uint height, PixelFormatID pixelFormat,
                                   InterpolationHint hints, out IBitmapImage bitmap);

        uint CreateBitmapFromBuffer(); // This is a place holder, note the lack of arguments 
        uint CreateImageDecoder(); // This is a place holder, note the lack of arguments 
        uint CreateImageEncoderToStream(); // This is a place holder, note the lack of arguments 
        uint CreateImageEncoderToFile(); // This is a place holder, note the lack of arguments 
        uint GetInstalledDecoders(); // This is a place holder, note the lack of arguments 
        uint GetInstalledEncoders(); // This is a place holder, note the lack of arguments 
        uint InstallImageCodec(); // This is a place holder, note the lack of arguments 
        uint UninstallImageCodec(); // This is a place holder, note the lack of arguments 
    }

    // Pulled from imaging.h in the Windows Mobile 5.0 Pocket PC SDK 
    [ComImport, Guid("327ABDA9-072B-11D3-9D7B-0000F81EF32E"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    [ComVisible(true)]
    public interface IImage
    {
        uint GetPhysicalDimension(out Size size);
        uint GetImageInfo(out ImageInfo info);
        uint SetImageFlags(uint flags);
        uint Draw(IntPtr hdc, ref Rectangle dstRect, IntPtr srcRect);
        // "Correct" declaration: uint Draw(IntPtr hdc, ref Rectangle dstRect, ref Rectangle srcRect); 
        uint PushIntoSink(); // This is a place holder, note the lack of arguments 
        uint GetThumbnail(uint thumbWidth, uint thumbHeight, out IImage thumbImage);
    }

    // Pulled from imaging.h in the Windows Mobile 5.0 Pocket PC SDK 
    [ComImport, Guid("327ABDAA-072B-11D3-9D7B-0000F81EF32E"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    [ComVisible(true)]
    public interface IBitmapImage
    {
        uint GetSize(out Size size);
        uint GetPixelFormatID(out PixelFormatID pixelFormat);
        uint LockBits(ref Rectangle rect, uint flags, PixelFormatID pixelFormat, out BitmapData lockedBitmapData);
        uint UnlockBits(ref BitmapData lockedBitmapData);
        uint GetPalette(); // This is a place holder, note the lack of arguments 
        uint SetPalette(); // This is a place holder, note the lack of arguments 
    }

    public static class XFControlUtils
    {
        private static object _logInfoLock = new object();

        [DllImport("coredll.dll")]
        public static extern void GlobalMemoryStatus(ref MEMORYSTATUS lpBuffer);

        public struct MEMORYSTATUS
        {
            public int dwLength;
            public int dwMemoryLoad;
            public int dwTotalPhys;
            public int dwAvailPhys;
            public int dwTotalPageFile;
            public int dwAvailPageFile;
            public int dwTotalVirtual;
            public int dwAvailVirtual;
        };

        const string CRLF = "\r\n";
        public static string GetMemoryStatus()
        {
            MEMORYSTATUS ms = new MEMORYSTATUS();
            ms.dwLength = Marshal.SizeOf(ms);
            GlobalMemoryStatus(ref ms);
            string strAppName = "Memory Status";
            StringBuilder sbMessage = new StringBuilder();
            sbMessage.Append("Memory Load = ");
            sbMessage.Append(ms.dwMemoryLoad + "%");
            sbMessage.Append(CRLF);
            sbMessage.Append("Total RAM = ");
            sbMessage.Append(ms.dwTotalPhys.ToString("#,##0"));
            sbMessage.Append(CRLF);
            sbMessage.Append("Avail RAM = ");
            sbMessage.Append(ms.dwAvailPhys.ToString("#,##0"));
            sbMessage.Append(CRLF);
            sbMessage.Append("Total Page = ");
            sbMessage.Append(ms.dwTotalPageFile.ToString("#,##0"));
            sbMessage.Append(CRLF);
            sbMessage.Append("Avail Page = ");
            sbMessage.Append(ms.dwAvailPageFile.ToString("#,##0"));
            sbMessage.Append(CRLF);
            sbMessage.Append("Total Virt = ");
            sbMessage.Append(ms.dwTotalVirtual.ToString("#,##0"));
            sbMessage.Append(CRLF);
            sbMessage.Append("Avail Virt = ");
            sbMessage.Append(ms.dwAvailVirtual.ToString("#,##0"));
            return sbMessage.ToString();
        }

        public static void LogInfo(string message, string type)
        {
            string debugFileName = GetCurrent_Directory() + "\\XDAFacebookDebug.xml";
            XDocument db = null;
            if (File.Exists(debugFileName))
            {
                try
                {
                    lock (_logInfoLock)
                        db = XDocument.Load(debugFileName);
                }
                catch (XmlException)
                {
                    db = new XDocument(
                        new XDeclaration("1.0", "utf-8", "yes"),
                        new XElement("debug"));
                }
            }
            else
                db = new XDocument(
                    new XDeclaration("1.0", "utf-8", "yes"),
                    new XElement("debug"));

            db.Root.Add(new XElement("message",
                new XAttribute("type", type),
                new XAttribute("date", DateTime.Now.ToString()), message));

            lock (_logInfoLock)
                db.Save(debugFileName);
        }


        public static void DrawAlpha(this Graphics gx, Bitmap image, byte transp, int x, int y)
        {
            using (Graphics gxSrc = Graphics.FromImage(image))
            {
                IntPtr hdcDst = gx.GetHdc();
                IntPtr hdcSrc = gxSrc.GetHdc();
                var blendFunction = new BlendFunction
                                        {
                                            BlendOp = (byte)BlendOperation.AC_SRC_OVER,
                                            BlendFlags = (byte)BlendFlags.Zero,
                                            SourceConstantAlpha = transp,
                                            AlphaFormat = 0
                                        };
                PlatformAPIs.AlphaBlend(hdcDst, x, y, image.Width, image.Height, hdcSrc, 0, 0, image.Width, image.Height,
                                        blendFunction);
                gxSrc.ReleaseHdc(hdcSrc); // Required cleanup to GetHdc()
                gx.ReleaseHdc(hdcDst); // Required cleanup to GetHdc()
            }
        }

        public static void DrawAlpha(this Graphics gx, Bitmap image, byte transp, Rectangle recDest, Rectangle recSrc)
        {
            using (Graphics gxSrc = Graphics.FromImage(image))
            {
                IntPtr hdcDst = gx.GetHdc();
                IntPtr hdcSrc = gxSrc.GetHdc();
                var blendFunction = new BlendFunction
                                        {
                                            BlendOp = (byte)BlendOperation.AC_SRC_OVER,
                                            BlendFlags = (byte)BlendFlags.Zero,
                                            SourceConstantAlpha = transp,
                                            AlphaFormat = 0
                                        };
                PlatformAPIs.AlphaBlend(hdcDst, recDest.X, recDest.Y, recDest.Width, recDest.Height, hdcSrc, recSrc.X,
                                        recSrc.Y, recSrc.Width, recSrc.Height, blendFunction);
                gx.ReleaseHdc(hdcDst); // Required cleanup to GetHdc()
                gxSrc.ReleaseHdc(hdcSrc); // Required cleanup to GetHdc()
            }
        }

        public static void DrawAlphaFirstPix(this Graphics gx, Bitmap image, int x, int y)
        {
            DrawAlphaFirstPix(gx, image, x, y, image.Width, image.Height);
        }

        public static void DrawAlphaFirstPix(this Graphics gx, Bitmap image, int x, int y, int width, int height)
        {
            var attrib = new ImageAttributes();
            Color color = GetTransparentColor(image);
            var clientArea = new Rectangle(x, y, width, height);

            attrib.SetColorKey(color, color);
            gx.DrawImage(image, clientArea, 0, 0, clientArea.Width, clientArea.Height,
                         GraphicsUnit.Pixel, attrib);
        }

        public static void DrawAlphaFirstPix(this Graphics gx, Bitmap image, int x, int y, int width, int height,
                                             int offset)
        {
            var attrib = new ImageAttributes();
            Color color = GetTransparentColor(image);
            var clientArea = new Rectangle(x, y, width, height);

            attrib.SetColorKey(color, color);
            gx.DrawImage(image, clientArea, offset, 0, clientArea.Width, clientArea.Height,
                         GraphicsUnit.Pixel, attrib);
        }

        public static void DrawAlphaFirstPix(this Graphics gx, Bitmap image, Rectangle recDest, Rectangle recSrc)
        {
            var attrib = new ImageAttributes();
            Color color = GetTransparentColor(image);

            attrib.SetColorKey(color, color);
            gx.DrawImage(image, recDest, recSrc.X, recSrc.Y, recSrc.Width, recSrc.Height,
                         GraphicsUnit.Pixel, attrib);
        }

        public static void DrawAlphaColor(this Graphics gx, Bitmap image, Color color, int x, int y)
        {
            var attrib = new ImageAttributes();
            var recDest = new Rectangle(x, y, image.Width, image.Height);

            attrib.SetColorKey(color, color);
            gx.DrawImage(image, recDest, x, y, image.Width, image.Height,
                         GraphicsUnit.Pixel, attrib);
        }

        public static void DrawAlphaColor(this Graphics gx, Bitmap image, Color color, Rectangle recDest,
                                          Rectangle recSrc)
        {
            var attrib = new ImageAttributes();

            attrib.SetColorKey(color, color);
            gx.DrawImage(image, recDest, recSrc.X, recSrc.Y, recSrc.Width, recSrc.Height,
                         GraphicsUnit.Pixel, attrib);
        }

        public static Bitmap CopyRegion(Bitmap srcBitmap, Rectangle section)
        {
            // Create the new bitmap and associated graphics object
            var bmp = XFBitmapFactory.GetBitmap(section.Width, section.Height);
            using (Graphics g = Graphics.FromImage(bmp))
            {
                // Draw the specified section of the source bitmap to the new one
                g.DrawImage(srcBitmap, section.X, section.Y);
            }
            // Return the bitmap
            return bmp;
        }

        public static void DrawJustifiedString(this Graphics g, int x, int y, int width, string text, Font textFont,
                                               Color c)
        {
            DrawJustifiedString(g, x, y, width, text, textFont, c, false);
        }

        public static void DrawJustifiedString(this Graphics g, int x, int y, int width, string text, Font textFont,
                                               Color c, bool format)
        {
            if (format)
                text = GetSizedString(width, text, textFont);

            int curX = x, curY = y;

            using (var b = new SolidBrush(c))
            {
                foreach (string line in text.Split('\n'))
                {
                    if (text.Split('\n').Last() == line)
                        g.DrawString(line, textFont, b, curX, curY);

                    else
                    {
                        string[] words = line.Split(' ');
                        SizeF lineMeasure = getLineMeasure(line, g, textFont);
                        int spaceWidth = (width - (int)lineMeasure.Width) /
                                         (words.Length > 1 ? words.Length - 1 : words.Length);

                        foreach (string word in words)
                        {
                            SizeF wordMeasure = g.MeasureString(word, textFont);
                            g.DrawString(word, textFont, b, curX, curY);
                            curX += (int)wordMeasure.Width + spaceWidth;
                        }

                        curY += (int)lineMeasure.Height;
                        curX = x;
                    }
                }
            }
        }

        public static void GradientFill(this Graphics graphics, Rectangle rectangle, Color startColor, Color endColor,
                                        GradientFillDirection direction)
        {
            var tva = new TRIVERTEX[2];
            tva[0] = new TRIVERTEX(rectangle.Right, rectangle.Bottom, endColor);
            tva[1] = new TRIVERTEX(rectangle.X, rectangle.Y, startColor);
            var gra = new[] { new GRADIENT_RECT(0, 1) };
            IntPtr hdc = graphics.GetHdc();
            try
            {
                PlatformAPIs.GradientFill(hdc, tva, (uint)tva.Length, gra, (uint)gra.Length, (uint)direction);
            }
            finally
            {
                graphics.ReleaseHdc(hdc);
            }
        }

        public static Size GetEllipsisStringMeasure(int width, string Text, Font TextFont)
        {
            Text = EllipsisWord(width, Text, TextFont);
            Size ret = TextFont.MeasureString(Text, new Rectangle(0, 0, width, 0));

            return ret;
        }

        public static string EllipsisWord(int width, string text, Font TextFont)
        {
            var sb = new StringBuilder();
            var sbLine = new StringBuilder();
            var rec = new Rectangle(0, 0, width << 1, 0);

            Size s = TextFont.MeasureString(text, rec);
            if (s.Width < width)
                return text;


            const string EllipsisChars = "...";
            int len = 0;
            int seg = text.Length;
            string fit = "";

            // find the longest string that fits into
            // the control boundaries using bisection method 
            while (seg > 1)
            {
                seg -= seg >> 1;

                int left = len + seg;
                int right = text.Length;

                if (left > right)
                    continue;


                // build and measure a candidate string with ellipsis
                string tst = text.Substring(0, left) +
                    EllipsisChars + text.Substring(right);

                s = TextFont.MeasureString(tst, rec);

                // candidate string fits into control boundaries, 
                // try a longer string
                // stop when seg <= 1 
                if (s.Width > width) continue;
                len += seg;
                fit = tst;
            }
            return len == 0 ? EllipsisChars : fit;
        }

        public static string GetSizedString(int width, string Text, Font TextFont)
        {
            if (string.IsNullOrEmpty(Text))
                return "";

            string buffer = "";
            string full = "";
            Rectangle rec = new Rectangle(0, 0, width << 1, 0);

            string[] words = Text.Split(' ');
            foreach (string s in words)
            {
                string temp;

                if (string.IsNullOrEmpty(buffer))
                    temp = s;
                else
                    temp = buffer + " " + s;
                Size tLength = TextFont.MeasureString(temp, rec);

                if (tLength.Width > width)
                {
                    if (string.IsNullOrEmpty(full))
                        full = buffer;
                    else
                        full += "\n" + buffer;
                    buffer = s;

                    if (TextFont.MeasureString(buffer, rec).Width > width)
                        buffer = splitWord(width, buffer, TextFont);
                }
                else
                {
                    buffer = temp;
                }
            }

            if (string.IsNullOrEmpty(full))
                full = buffer;
            else
                full += "\n" + buffer;

            return full;
        }

        public static void DrawBackground(this Graphics g, object sender, XFItemStyle Style, int x, int y, int width,
                                          int height)
        {
            DrawBackground(sender, Style, g, x, y, width, height);
        }

        public static void DrawBackgroundSelected(this Graphics g, object sender, XFItemStyle Style, int x, int y,
                                                  int width, int height)
        {
            DrawBackgroundSelected(sender, Style, g, x, y, width, height);
        }

        public static void DrawBackgroundDisabled(this Graphics g, object sender, XFItemStyle Style, int x, int y,
                                                  int width, int height)
        {
            DrawBackgroundDisabled(sender, Style, g, x, y, width, height);
        }

        public static void DrawBackground(object sender, XFItemStyle Style, Graphics g, int x, int y, int width,
                                          int height)
        {
            var destRec = new Rectangle(x, y, width, height);
            if (string.IsNullOrEmpty(Style.BackgroundImageString))
            {
                if (Style.BackgroundImage == null)
                {
                    using (var b = new SolidBrush(Style.BackgroundColor))
                        g.FillRectangle(b, x, y, width, height);

                    return;
                }
                var srcRec = new Rectangle(0, 0, Style.BackgroundImage.Width, Style.BackgroundImage.Height);

                g.DrawImage(Style.BackgroundImage, destRec, srcRec, GraphicsUnit.Pixel);
            }
            g.DrawUIAlphaChannel(sender, Style.BackgroundImageString, destRec);
        }

        public static void DrawBackgroundSelected(object sender, XFItemStyle Style, Graphics g, int x, int y, int width,
                                                  int height)
        {
            var destRec = new Rectangle(x, y, width, height);
            if (string.IsNullOrEmpty(Style.SelectedBackgroundImageString))
            {
                if (Style.SelectedBackgroundImage == null)
                {
                    using (var b = new SolidBrush(Style.SelectedBackgroundColor))
                        g.FillRectangle(b, x, y, width, height);

                    return;
                }
                var srcRec = new Rectangle(0, 0, Style.SelectedBackgroundImage.Width,
                                           Style.SelectedBackgroundImage.Height);

                g.DrawImage(Style.SelectedBackgroundImage, destRec, srcRec, GraphicsUnit.Pixel);
            }
            g.DrawUIAlphaChannel(sender, Style.SelectedBackgroundImageString, destRec);
        }

        public static void DrawBackgroundDisabled(object sender, XFItemStyle Style, Graphics g, int x, int y, int width,
                                                  int height)
        {
            var destRec = new Rectangle(x, y, width, height);
            if (string.IsNullOrEmpty(Style.DisabledBackgroundImageString))
            {
                if (Style.DisabledBackgroundImage == null)
                {
                    using (var b = new SolidBrush(Style.DisabledBackgroundColor))
                        g.FillRectangle(b, x, y, width, height);

                    return;
                }
                var srcRec = new Rectangle(0, 0, Style.DisabledBackgroundImage.Width,
                                           Style.DisabledBackgroundImage.Height);

                g.DrawImage(Style.SelectedBackgroundImage, destRec, srcRec, GraphicsUnit.Pixel);
            }
            g.DrawUIAlphaChannel(sender, Style.DisabledBackgroundImageString, destRec);
        }

        public static void DrawBorders(XFItemStyle Style, Graphics g, int x, int y, int width, int height)
        {
            if(Style == null)
                return;
            
            if (Style.BorderBottom)
                using (var p = new Pen(Style.BorderBottomColor) { DashStyle = Style.DashStyleBottom })
                    g.DrawLine(p, x, y + (height - 1), width, y + (height - 1));
            if (Style.BorderLeft)
                using (var p = new Pen(Style.BorderLeftColor) { DashStyle = Style.DashStyleLeft })
                    g.DrawLine(p, x, y + 1, x, y + (height - 1));
            if (Style.BorderRight)
                using (var p = new Pen(Style.BorderRightColor) { DashStyle = Style.DashStyleRight })
                    g.DrawLine(p, width, y + 1, width, y + (height - 1));
            if (Style.BorderTop)
                using (var p = new Pen(Style.BorderTopColor) { DashStyle = Style.DashStyleTop })
                    g.DrawLine(p, x, y + 1, width, y + 1);
        }

        public static void DrawBorders(this Graphics g, XFItemStyle Style, int x, int y, int width, int height)
        {
            DrawBorders(Style, g, x, y, width, height);
        }

        public static void DrawBlackout(this Graphics g, Rectangle _blackout)
        {
            using (var img = XFBitmapFactory.GetBitmap(_blackout.Width, _blackout.Height))
            {
                using (Graphics gf = Graphics.FromImage(img))
                using (var b = new SolidBrush(Color.Black))
                    gf.FillRectangle(b, 0, 0, _blackout.Width, _blackout.Height);

                DrawAlpha(g, img, 200, _blackout.X, _blackout.Y);
            }
        }

        public static void DrawBlackout(this Graphics g, Rectangle _blackout, byte amount)
        {
            using (var img = XFBitmapFactory.GetBitmap(_blackout.Width, _blackout.Height))
            {
                using (Graphics gf = Graphics.FromImage(img))
                using (var b = new SolidBrush(Color.Black))
                    gf.FillRectangle(b, 0, 0, _blackout.Width, _blackout.Height);

                DrawAlpha(g, img, amount, _blackout.X, _blackout.Y);
            }
        }

        public static string GetCurrent_Directory()
        {
            return Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetName().CodeBase);
        }

        public static string Decrypt(this string value)
        {
            value = ConvertToASCII(value);
            byte[] binary = Encoding.UTF8.GetBytes(value);
            byte[] key = Encoding.UTF8.GetBytes("This is the key file");
            var encrypted = new byte[binary.Length];
            for (int i = 0, j = 0; i < binary.Length; i++)
            {
                encrypted[i] = Convert.ToByte(binary[i] ^ key[j]);
                if (j < key.Length - 1)
                    j++;
                else
                    j = 0;
            }
            return Encoding.UTF8.GetString(encrypted, 0, encrypted.Length);
        }

        public static string Encrypt(this string password)
        {
            byte[] binary = Encoding.UTF8.GetBytes(password);
            byte[] key = Encoding.UTF8.GetBytes("This is the key file");
            var encrypted = new byte[binary.Length];
            for (int i = 0, j = 0; i < binary.Length; i++)
            {
                encrypted[i] = Convert.ToByte(binary[i] ^ key[j]);
                if (j < key.Length - 1)
                    j++;
                else
                    j = 0;
            }
            string ret = Encoding.UTF8.GetString(encrypted, 0, encrypted.Length);
            ret = ConvertToHex(ret);
            return ret;
        }

        public static bool Contains(this string str, string value, StringComparison comparisonType)
        {
            return str.IndexOf(value, comparisonType) >= 0;
        }

        public static Rectangle ScaleToFitInside(this Rectangle recSrc, Rectangle recDest, bool fitSrc)
        {
            if (recDest.Width < recSrc.Width && recDest.Height < recSrc.Height)
            {
                int newX = ((recSrc.Width - recDest.Width) / 2);
                int newY = ((recSrc.Height - recDest.Height) / 2);
                return new Rectangle(newX, newY, recDest.Width, recDest.Height);
            }

            if (recDest.Width - recSrc.Width > recDest.Height - recSrc.Height)
            {
                double ammount = recDest.Width - recSrc.Width;
                double ratio = ammount / recDest.Width;

                int newHeight = recDest.Height - (int)(recDest.Height * ratio);
                int newY = ((recSrc.Height - newHeight) / 2);

                if (fitSrc)
                    return new Rectangle(0, newY, (int)(recDest.Width - ammount),
                                         recDest.Height - (int)(recDest.Height * ratio));

                return new Rectangle(0, 0, (int)(recDest.Width - ammount),
                                     recDest.Height - (int)(recDest.Height * ratio));
            }
            else
            {
                double ammount = recDest.Height - recSrc.Height;
                double ratio = ammount / recDest.Height;

                int newWidth = recDest.Width - (int)(recDest.Width * ratio);
                int newX = ((recSrc.Width - newWidth) / 2);

                int newHeight = recDest.Height - (int)(recDest.Height * ratio);
                int newY = ((recSrc.Height - newHeight) / 2);

                if (fitSrc)
                    return new Rectangle(newX, newY, newWidth, (int)(recDest.Height - ammount));

                return new Rectangle(0, 0, newWidth, (int)(recDest.Height - ammount));
            }
        }

        private static string ConvertToHex(string asciiString)
        {
            var hex = new StringBuilder();
            foreach (char c in asciiString)
            {
                int tmp = c;
                hex.AppendFormat("{0:x2}", Convert.ToUInt32(tmp.ToString()));
            }
            return hex.ToString();
        }

        private static string ConvertToASCII(string hexString)
        {
            string str = "";
            string temp = "";
            try
            {
                foreach (char ch in hexString)
                {
                    if (!string.IsNullOrEmpty(temp))
                    {
                        temp += ch.ToString();
                        byte newByte = byte.Parse(temp, NumberStyles.HexNumber);
                        int i = Convert.ToInt32(newByte.ToString()); // i now = 65
                        str += Convert.ToChar(i);
                        temp = "";
                    }
                    else
                    {
                        temp = ch.ToString();
                    }
                }
            }
            catch { }
            return str;
        }

        private static string splitWord(int width, string Text, Font TextFont)
        {
            var sb = new StringBuilder();
            var sbLine = new StringBuilder();
            Rectangle rec = new Rectangle(0, 0, width << 1, 0);

            foreach (char s in Text)
            {
                sbLine.Append(s);

                Size tLength = TextFont.MeasureString(sbLine.ToString(), rec);

                if (tLength.Width > width)
                {
                    sb.Append("\n").Append(s);
                    sbLine = new StringBuilder(s);
                }
                else
                    sb.Append(s);
            }
            return sb.ToString();
        }

        private static SizeF getLineMeasure(string line, Graphics g, Font textFont)
        {
            string temp = line.Replace(" ", "");
            return g.MeasureString(temp, textFont);
        }

        private static Color GetTransparentColor(Bitmap image)
        {
            return image.GetPixel(0, 0);
        }
    }

    internal class ImageRequest
    {
        public ImageRequest(IXFItem item, string uri, List<XFGraphics.GetImageDelegate> callbacks)
        {
            Item = item;
            Uri = uri;
            Callbacks = callbacks;
        }

        public bool Cancelled;
        public IXFItem Item { get; set; }
        public string Uri { get; set; }
        public List<XFGraphics.GetImageDelegate> Callbacks { get; set; }
    }
}

// ReSharper restore RedundantAssignment
// ReSharper restore EmptyGeneralCatchClause
// ReSharper restore BitwiseOperatorOnEnumWihtoutFlags
// ReSharper restore PossibleNullReferenceException
// ReSharper restore EnumUnderlyingTypeIsInt
// ReSharper restore UnaccessedField.Local
// ReSharper restore InconsistentNaming

#pragma warning restore 168
#pragma warning restore 219
#pragma warning restore 1591